package com.flying.client.network;

import java.util.ArrayList;
import java.util.List;

import com.flying.client.network.NetworkClient.IAsyncSink;
import com.flying.client.network.msg.ORMsg;
import com.flying.client.network.msg.OWMsg;
import com.flying.client.utils.Logger;

public class NetworkProvider {
	private static final Logger logger = Logger.getLogger(NetworkProvider.class.getName());
	
	private enum NetworkStatus
	{
		STATUS_CONNECTING,STATUS_CONNECTED,STATUS_DISCONNECTION,STATUS_CLOSEED;
	};

	private Object clientLocker = new Object();
	/**
	 * 当前可用网络客户端
	 */
	private NetworkClient curClient;
	/**
	 * 状态锁
	 */
	private Object statusLocker = new Object();
	/**
	 * 网络提供者状态
	 */
	private NetworkStatus status = NetworkStatus.STATUS_DISCONNECTION;
	/**
	 * 网络客户端列表
	 */
	private List<NetworkClient> clientList = new ArrayList<NetworkClient>();
	
	/**
	 * 网络回调
	 */
	private INetworkSink sink;
	
	private ConnAsyncSink connAsyncSink = new ConnAsyncSink();
	
	public NetworkProvider(INetworkSink sink)
	{
		this.sink = sink;
	}
	/**
	 * 加入服务信息
	 * @param serverIp
	 * @param serverPort
	 */
	public void addServerInfo(String serverIp,int serverPort)
	{
		synchronized(this.clientLocker)
		{
			this.clientList.add(new NetworkClient(this,serverIp,serverPort));
		}
	}
	
	/**
	 * 网络连接
	 * @return
	 */
	public synchronized boolean connect()
	{
		logger.debug("connect curClient="+curClient);
		if (this.curClient != null && this.curClient.isValid())
			return false;
		
		try
		{
			for(int i = 0 ;i<clientList.size();i++)
			{
				NetworkClient client = clientList.get(i);
				client.init();
				client.asyncConnect(connAsyncSink);
			}
		}
		catch(Exception e)
		{
			logger.error("connect Error="+e);
		}
		
		return false;
	}
	/**
	 * 关闭网络
	 * @return
	 */
	public synchronized boolean close()
	{
		if (this.curClient == null)
			return false;
		
		boolean flag = this.curClient.close();
		
		synchronized(this)
		{
			this.curClient = null;
		}
		return flag;
	}
	/**
	 * 发送消息（只加入到等待发送队列）
	 */
	public boolean send(OWMsg msg)
	{
		if (this.curClient == null)
			return false;
		
		return this.curClient.send(msg);
	}
	/**
	 * 设置状态
	 * @param status
	 */
	private void setStatus(NetworkStatus status)
	{
		synchronized(this.statusLocker)
		{
			if (this.status != status)
			{
				this.status = status;
			}
		}
	}
	
	/**
	 * 是否可写
	 * @return
	 */
	public boolean canWrite()
	{
		logger.debug("canWrite curClient="+curClient+" valid="+curClient.isValid()+" canWrite="+curClient.canWrite());
		return this.curClient != null && this.curClient.isValid() && this.curClient.canWrite();
	}
	/**
	 * 连接事件
	 * @param success
	 * @param client
	 */
	void onConnected(int success,NetworkClient client)
	{
		if (this.sink != null)
		{
			this.sink.onConnected(new NetworkResult(success,client));
		}
		
		this.setStatus(NetworkStatus.STATUS_CONNECTED);
	}
	/**
	 * 关闭事件
	 * @param client
	 */
	void onClosed(NetworkClient client)
	{
		if (this.sink != null)
		{
			this.sink.onClosed(new NetworkResult(client));
		}
		this.setStatus(NetworkStatus.STATUS_CLOSEED);
	}
	/**
	 * 被关闭网络事件
	 * @param client
	 */
	void onDisconnection(NetworkClient client)
	{
		if (this.sink != null)
		{
			this.sink.onDisConnectioned(new NetworkResult(NetworkResult.STATUS_SUCCESSED,client));
		}
		this.setStatus(NetworkStatus.STATUS_DISCONNECTION);
	}
	/**
	 * 网络错误事件
	 * @param throwable
	 * @param client
	 */
	void onError(Throwable throwable,NetworkClient client)
	{
		if (this.sink != null)
		{
			this.sink.onError(throwable,client);
		}
	}
	/**
	 * 接收消息
	 * @param rMsg
	 */
	void onReceivedMsg(ORMsg rMsg)
	{
		if (this.sink != null)
		{
			this.sink.onReceivedMsg(rMsg);
		}
	}
	
	class ConnAsyncSink implements IAsyncSink
	{
		@Override
		public void onResult(boolean conned,NetworkClient client) {
			
			synchronized(clientLocker)
			{
				if (conned)
				{
					NetworkProvider.this.curClient = client;
					onConnected(NetworkResult.STATUS_SUCCESSED, client);
				}
			}
		}
	}
}
